home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / snprintf.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  17KB  |  771 lines

  1. #include "config.h"
  2.  
  3. #ifndef HAVE_SNPRINTF
  4.  
  5. #include <ctype.h>
  6. #include <sys/types.h>
  7.  
  8. /* Define this as a fall through, HAVE_STDARG_H is probably already set */
  9.  
  10. #define HAVE_VARARGS_H
  11.  
  12. /**************************************************************
  13.  * Original:
  14.  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
  15.  * A bombproof version of doprnt (dopr) included.
  16.  * Sigh.  This sort of thing is always nasty do deal with.  Note that
  17.  * the version here does not include floating point...
  18.  *
  19.  * snprintf() is used instead of sprintf() as it does limit checks
  20.  * for string length.  This covers a nasty loophole.
  21.  *
  22.  * The other functions are there to prevent NULL pointers from
  23.  * causing nast effects.
  24.  *
  25.  * More Recently:
  26.  *  Brandon Long (blong@fiction.net) 9/15/96 for mutt 0.43
  27.  *  This was ugly.  It is still ugly.  I opted out of floating point
  28.  *  numbers, but the formatter understands just about everything
  29.  *  from the normal C string format, at least as far as I can tell from
  30.  *  the Solaris 2.5 printf(3S) man page.
  31.  *
  32.  *  Brandon Long (blong@fiction.net) 10/22/97 for mutt 0.87.1
  33.  *    Ok, added some minimal floating point support, which means this
  34.  *    probably requires libm on most operating systems.  Don't yet
  35.  *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
  36.  *    was pretty badly broken, it just wasn't being exercised in ways
  37.  *    which showed it, so that's been fixed.  Also, formated the code
  38.  *    to mutt conventions, and removed dead code left over from the
  39.  *    original.  Also, there is now a builtin-test, just compile with:
  40.  *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
  41.  *    and run snprintf for results.
  42.  *
  43.  **************************************************************/
  44.  
  45.  
  46. /* varargs declarations: */
  47.  
  48. #if defined(HAVE_STDARG_H)
  49. # include <stdarg.h>
  50. # define HAVE_STDARGS    /* let's hope that works everywhere (mj) */
  51. # define VA_LOCAL_DECL   va_list ap
  52. # define VA_START(f)     va_start(ap, f)
  53. # define VA_SHIFT(v,t)  ;   /* no-op for ANSI */
  54. # define VA_END          va_end(ap)
  55. #else
  56. # if defined(HAVE_VARARGS_H)
  57. #  include <varargs.h>
  58. #  undef HAVE_STDARGS
  59. #  define VA_LOCAL_DECL   va_list ap
  60. #  define VA_START(f)     va_start(ap)      /* f is ignored! */
  61. #  define VA_SHIFT(v,t) v = va_arg(ap,t)
  62. #  define VA_END        va_end(ap)
  63. # else
  64. /*XX ** NO VARARGS ** XX*/
  65. # endif
  66. #endif
  67.  
  68. int snprintf (char *str, size_t count, const char *fmt, ...);
  69. int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
  70.  
  71. static void dopr (char *buffer, size_t maxlen, const char *format, 
  72.                   va_list args);
  73. static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
  74.             char *value, int flags, int min, int max);
  75. static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
  76.             long value, int base, int min, int max, int flags);
  77. static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
  78.            long double fvalue, int min, int max, int flags);
  79. static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
  80.  
  81. int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
  82. {
  83.   str[0] = 0;
  84.   dopr(str, count, fmt, args);
  85.   return(strlen(str));
  86. }
  87.  
  88. /* VARARGS3 */
  89. #ifdef HAVE_STDARGS
  90. int snprintf (char *str,size_t count,const char *fmt,...)
  91. #else
  92. int snprintf (va_alist) va_dcl
  93. #endif
  94. {
  95. #ifndef HAVE_STDARGS
  96.   char *str;
  97.   size_t count;
  98.   char *fmt;
  99. #endif
  100.   VA_LOCAL_DECL;
  101.     
  102.   VA_START (fmt);
  103.   VA_SHIFT (str, char *);
  104.   VA_SHIFT (count, size_t );
  105.   VA_SHIFT (fmt, char *);
  106.   (void) vsnprintf(str, count, fmt, ap);
  107.   VA_END;
  108.   return(strlen(str));
  109. }
  110.  
  111. /*
  112.  * dopr(): poor man's version of doprintf
  113.  */
  114.  
  115. /* format read states */
  116. #define DP_S_DEFAULT 0
  117. #define DP_S_FLAGS   1
  118. #define DP_S_MIN     2
  119. #define DP_S_DOT     3
  120. #define DP_S_MAX     4
  121. #define DP_S_MOD     5
  122. #define DP_S_CONV    6
  123. #define DP_S_DONE    7
  124.  
  125. /* format flags - Bits */
  126. #define DP_F_MINUS 1
  127. #define DP_F_PLUS  2
  128. #define DP_F_SPACE 4
  129. #define DP_F_NUM   8
  130. #define DP_F_ZERO  16
  131. #define DP_F_UP    32
  132.  
  133. /* Conversion Flags */
  134. #define DP_C_SHORT   1
  135. #define DP_C_LONG    2
  136. #define DP_C_LDOUBLE 3
  137.  
  138. #define char_to_int(p) (p - '0')
  139. #define MAX(p,q) ((p >= q) ? p : q)
  140.  
  141. static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
  142. {
  143.   char ch;
  144.   long value;
  145.   long double fvalue;
  146.   char *strvalue;
  147.   int min;
  148.   int max;
  149.   int state;
  150.   int flags;
  151.   int cflags;
  152.   size_t currlen;
  153.   
  154.   state = DP_S_DEFAULT;
  155.   currlen = flags = cflags = min = 0;
  156.   max = -1;
  157.   ch = *format++;
  158.  
  159.   while (state != DP_S_DONE)
  160.   {
  161.     if ((ch == '\0') || (currlen >= maxlen)) 
  162.       state = DP_S_DONE;
  163.  
  164.     switch(state) 
  165.     {
  166.     case DP_S_DEFAULT:
  167.       if (ch == '%') 
  168.     state = DP_S_FLAGS;
  169.       else 
  170.     dopr_outch (buffer, &currlen, maxlen, ch);
  171.       ch = *format++;
  172.       break;
  173.     case DP_S_FLAGS:
  174.       switch (ch) 
  175.       {
  176.       case '-':
  177.     flags |= DP_F_MINUS;
  178.         ch = *format++;
  179.     break;
  180.       case '+':
  181.     flags |= DP_F_PLUS;
  182.         ch = *format++;
  183.     break;
  184.       case ' ':
  185.     flags |= DP_F_SPACE;
  186.         ch = *format++;
  187.     break;
  188.       case '#':
  189.     flags |= DP_F_NUM;
  190.         ch = *format++;
  191.     break;
  192.       case '0':
  193.     flags |= DP_F_ZERO;
  194.         ch = *format++;
  195.     break;
  196.       default:
  197.     state = DP_S_MIN;
  198.     break;
  199.       }
  200.       break;
  201.     case DP_S_MIN:
  202.       if (isdigit(ch)) 
  203.       {
  204.     min = 10*min + char_to_int (ch);
  205.     ch = *format++;
  206.       } 
  207.       else if (ch == '*') 
  208.       {
  209.     min = va_arg (args, int);
  210.     ch = *format++;
  211.     state = DP_S_DOT;
  212.       } 
  213.       else 
  214.     state = DP_S_DOT;
  215.       break;
  216.     case DP_S_DOT:
  217.       if (ch == '.') 
  218.       {
  219.     state = DP_S_MAX;
  220.     ch = *format++;
  221.       } 
  222.       else 
  223.     state = DP_S_MOD;
  224.       break;
  225.     case DP_S_MAX:
  226.       if (isdigit(ch)) 
  227.       {
  228.     if (max < 0)
  229.       max = 0;
  230.     max = 10*max + char_to_int (ch);
  231.     ch = *format++;
  232.       } 
  233.       else if (ch == '*') 
  234.       {
  235.     max = va_arg (args, int);
  236.     ch = *format++;
  237.     state = DP_S_MOD;
  238.       } 
  239.       else 
  240.     state = DP_S_MOD;
  241.       break;
  242.     case DP_S_MOD:
  243.       /* Currently, we don't support Long Long, bummer */
  244.       switch (ch) 
  245.       {
  246.       case 'h':
  247.     cflags = DP_C_SHORT;
  248.     ch = *format++;
  249.     break;
  250.       case 'l':
  251.     cflags = DP_C_LONG;
  252.     ch = *format++;
  253.     break;
  254.       case 'L':
  255.     cflags = DP_C_LDOUBLE;
  256.     ch = *format++;
  257.     break;
  258.       default:
  259.     break;
  260.       }
  261.       state = DP_S_CONV;
  262.       break;
  263.     case DP_S_CONV:
  264.       switch (ch) 
  265.       {
  266.       case 'd':
  267.       case 'i':
  268.     if (cflags == DP_C_SHORT) 
  269.       value = va_arg (args, short int);
  270.     else if (cflags == DP_C_LONG)
  271.       value = va_arg (args, long int);
  272.     else
  273.       value = va_arg (args, int);
  274.     fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
  275.     break;
  276.       case 'o':
  277.     flags &= ~DP_F_PLUS;
  278.     if (cflags == DP_C_SHORT)
  279.       value = va_arg (args, unsigned short int);
  280.     else if (cflags == DP_C_LONG)
  281.       value = va_arg (args, unsigned long int);
  282.     else
  283.       value = va_arg (args, unsigned int);
  284.     fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
  285.     break;
  286.       case 'u':
  287.     flags &= ~DP_F_PLUS;
  288.     if (cflags == DP_C_SHORT)
  289.       value = va_arg (args, unsigned short int);
  290.     else if (cflags == DP_C_LONG)
  291.       value = va_arg (args, unsigned long int);
  292.     else
  293.       value = va_arg (args, unsigned int);
  294.     fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
  295.     break;
  296.       case 'X':
  297.     flags |= DP_F_UP;
  298.       case 'x':
  299.     flags &= ~DP_F_PLUS;
  300.     if (cflags == DP_C_SHORT)
  301.       value = va_arg (args, unsigned short int);
  302.     else if (cflags == DP_C_LONG)
  303.       value = va_arg (args, unsigned long int);
  304.     else
  305.       value = va_arg (args, unsigned int);
  306.     fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
  307.     break;
  308.       case 'f':
  309.     if (cflags == DP_C_LDOUBLE)
  310.       fvalue = va_arg (args, long double);
  311.     else
  312.       fvalue = va_arg (args, double);
  313.     /* um, floating point? */
  314.     fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
  315.     break;
  316.       case 'E':
  317.     flags |= DP_F_UP;
  318.       case 'e':
  319.     if (cflags == DP_C_LDOUBLE)
  320.       fvalue = va_arg (args, long double);
  321.     else
  322.       fvalue = va_arg (args, double);
  323.     break;
  324.       case 'G':
  325.     flags |= DP_F_UP;
  326.       case 'g':
  327.     if (cflags == DP_C_LDOUBLE)
  328.       fvalue = va_arg (args, long double);
  329.     else
  330.       fvalue = va_arg (args, double);
  331.     break;
  332.       case 'c':
  333.     dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
  334.     break;
  335.